﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnitLibrary.Managers;
using UnitLibrary;
using Microsoft.Xna.Framework;
using FarseerGames.FarseerPhysics;
using Microsoft.Xna.Framework.Graphics;
using UnitLibrary.GameObjects.Physics;
using Microsoft.Xna.Framework.Content;
using UnitLibrary.GameObjects.UnitReaders;
using FarseerGames.FarseerPhysics.Collisions;

namespace UnitLibrary.GameObjects.Units
{
    public delegate int GetDamage(Iid id);

    public class Enemy: UnitGen
    {
        public Enemy()
            : base()
        {
            _damageTakenStack = new Stack<DamageContainer>();
        }

        #region Properties and Values

        #region Private
       
        /// <summary>
        /// The ai type of this enemy
        /// </summary>
        private AIType aiType = AIType.Player;

        /// <summary>
        /// enemy name
        /// </summary>
        private string _enemyName = "Enemy";

        /// <summary>
        /// the generic unit type for this enemy
        /// </summary>
        private string _unitGenericName = "default";

        private AIMovement aiMovement = AIMovement.Vulture;

        private double _aiUpdateDelay = 100;

        private double _timer = 0;

        private bool _isDamageTaken = false;

        public int NumberOfPoints = 10;

        public string PointName = "Default";

        private struct DamageContainer
        {
            public DamageContainer(int damageAmount)
            {
                Damage = damageAmount;
                Age = 0;
            }
            public int Damage;
            public double Age;
        }

        private Stack<DamageContainer> _damageTakenStack;

        private SpriteFont _damageFont;

#endregion

        #region Public

        
        /// <summary>
        /// Public get set for AI Type so AI Manager can change it's type if need be
        /// </summary>
        public AIType AiType
        {
            get { return aiType; }
            set { aiType = value; }
        }
#region Public

        /// <summary>
        /// Publicly exposed enemy name to get
        /// Can't set enemy name after it's already been set
        /// </summary>
        public string EnemyName
        {
            get { return _enemyName; }
            set
            {
                
                    _enemyName = value;
                
            }
        }

        [ContentSerializerIgnore]
        public AIMovement AiMovement
        {
            get { return aiMovement; }
            set { aiMovement = value; }
        }

        [ContentSerializerIgnore]
        public double AIUpdateDelay
        {
            get { return _aiUpdateDelay; }
            set { _aiUpdateDelay = value; }
        }
        
#endregion

        #endregion

        

        /// <summary>
        /// 
        /// </summary>
        /// <param name="geom1"></param>
        /// <param name="geom2"></param>
        /// <param name="contactlist"></param>
        /// <returns></returns>
        public bool OnCollision(Geom geom1, Geom geom2, ContactList contactlist)
        {
            Iid g1tag = (Iid)geom1.Tag;
            Iid g2tag = (Iid)geom2.Tag;
            //Geom 2 tag was never created, we don't know the type, so just return true

            if (geom1.Tag == null)
            {
                Console.WriteLine("Geom 1 tag inside of Enemy.cs OnCollision was never instantiated");
                //Return true since we don't know what the geoms are
                return true;
            }
            if (geom2.Tag == null)
            {
                Console.WriteLine("Geom 2 tag inside of Enemy.cs OnCollision was never instantiated");
                //Return true since we don't know what the geoms are
                return true;
            }
            //Make sure it's an enemy
            if (g1tag.UnitID == UnitID.Enemy)
            {
                //Go through the different types of unit ids
                switch (g2tag.UnitID)
                {
                    case UnitID.Bullet:
                        _components.particleEffects.TriggerEmitter("explosion", contactlist[0].Position);
                        TakeDamage(_components.GetDamage(g2tag));
                        return true;
                    case UnitID.Player:
                        this._body.ApplyImpulse(-this._moveDirection * this._moveSpeed * this._body.Mass);
                        return true;
                    case UnitID.Enemy:
                        return false;
                    default:
                        //TakeDamage(_components.GetDamage(g2tag));
                        return true;
                }
            }
            //If it's not, then we don't care, return true, let the other object handle it
            else
                return true;
        }

        public void TakeDamage(int damageAmount)
        {
            //Take damage
            this.Health -= damageAmount;
            if (Health < 0)
            {
                if (this.ID.UnitID == UnitID.Enemy)
                {
                    _components.RemoveUnit(this.ID, true);
                }
            }
        }
        #endregion

        #region IGameObject

        /// <summary>
        /// Draw extra stuff
        /// </summary>
        /// <param name="spriteBatch"></param>
        public override void Draw(SpriteBatch spriteBatch)
        {
            Vector2 location = this.Position;
            location.X += 5f;
            base.Draw(spriteBatch);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="gametime"></param>
        public override void Update(GameTime gametime)
        {
            _timer += gametime.ElapsedGameTime.Milliseconds;
            if (_timer > _aiUpdateDelay)
                base.SetMoveDirection(_components.playerManager.Player.Position);                
            base.Update(gametime);
        }

        public override void Create(object genericUnit,ComponentM components, Vector2 location, Vector2 direction, bool addtophysics)
        {
            base.Create(genericUnit, components, location, direction, addtophysics);
            Enemy enemy = (Enemy)genericUnit;
            //No need to go through and copy everything over again if it's already the right type of enemy
            this.aiType = enemy.aiType;
            this._enemyName = enemy.EnemyName;
            //Set the base geom collision to this units collision
            if(ObjectOnCollision == null)
                ObjectOnCollision += this.OnCollision;
        }

        public override void Remove(bool RemoveRefFromPhysics)
        {
            _components.pointsM.AddPointObjects(10, "default", this.Position);
            base.Remove(RemoveRefFromPhysics);
        }
        #endregion

        public override void ReadContent(ContentReader input)
        {
            base.ReadContent(input);
            this.aiType = input.ReadObject<AIType>();
            this._enemyName = input.ReadString();
        }
    }
}